package com.iteaj.iot.boot.autoconfigure;

import com.iteaj.iot.ComponentFactory;
import com.iteaj.iot.DeviceManagerFactory;
import com.iteaj.iot.boot.condition.ConditionalOnIotServer;
import com.iteaj.iot.boot.core.IotCoreConfiguration;
import com.iteaj.iot.business.ProtocolHandleFactory;
import com.iteaj.iot.server.DefaultDeviceManagerFactory;
import com.iteaj.iot.server.DefaultServerBootstrapInitializing;
import com.iteaj.iot.server.ServerBootstrapInitializing;
import com.iteaj.iot.server.endpoints.ServerHealthWebsocketEndpoint;
import com.iteaj.iot.server.udp.impl.DefaultUdpServerComponent;
import com.iteaj.iot.server.websocket.WebSocketServerListener;
import com.iteaj.iot.server.websocket.impl.DefaultWebSocketServerComponent;
import com.iteaj.iot.server.websocket.impl.DefaultWebSocketServerProtocolHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;

import java.util.HashMap;
import java.util.Map;

/**
 * Create Date By 2021-09-06
 *  <h4>设备网络通信程序启动入口</h4>
 * @author teaj
 * @since 1.7
 */
@Order(88158)
@ConditionalOnIotServer
@AutoConfigureAfter(IotCoreConfiguration.class)
@EnableConfigurationProperties({IotServerProperties.class})
public class IotServerConfiguration {

    protected ApplicationContext applicationContext;
    public final ComponentFactory componentFactory;
    public final ProtocolHandleFactory protocolHandleFactory;

    private static Logger logger = LoggerFactory.getLogger(IotServerConfiguration.class);

    public IotServerConfiguration(ApplicationContext applicationContext
            , ComponentFactory componentFactory, ProtocolHandleFactory protocolHandleFactory) {
        this.applicationContext = applicationContext;
        this.componentFactory = componentFactory;
        this.protocolHandleFactory = protocolHandleFactory;
    }

    @Bean
    @ConditionalOnMissingBean(DeviceManagerFactory.class)
    public DefaultDeviceManagerFactory deviceManagerFactory() {
        return new DefaultDeviceManagerFactory();
    }

    @Bean
    @ConditionalOnProperty(prefix = "iot.server.udp", name = "start", havingValue = "true")
    public DefaultUdpServerComponent defaultUdpServerComponent(IotServerProperties properties) {
        return new DefaultUdpServerComponent(properties.getUdp());
    }

    @Bean
    @ConditionalOnMissingBean(ServerBootstrapInitializing.class)
    public ServerBootstrapInitializing serverBootstrapInitializing() {
        return new DefaultServerBootstrapInitializing();
    }

    @Bean
    @ConditionalOnProperty(prefix = "iot.server", name = "websocket.start", havingValue = "true")
    public DefaultWebSocketServerComponent defaultWebSocketServerComponent(IotServerProperties properties) {
        return new DefaultWebSocketServerComponent(properties.getWebsocket());
    }

    @Bean
    @ConditionalOnBean(DefaultWebSocketServerComponent.class)
    public DefaultWebSocketServerProtocolHandle defaultWebSocketProtocolHandle(ObjectProvider<WebSocketServerListener> listeners) {
        Map<String, WebSocketServerListener> listenerMap = new HashMap<>();
        listeners.forEach(item -> {
            WebSocketServerListener listener = listenerMap.get(item.uri());
            if(listener != null) {
                // 监听器不支持一对多
                throw new BeanInitializationException("此uri["+item.uri()+"]已经配置WebSocket监听器["+listener.getClass().getSimpleName()+"]");
            }

            listenerMap.put(item.uri(), item);
        });

        if(listenerMap.size() == 0) {
            this.logger.warn("WebSocket默认组件未指定任何监听器["+ WebSocketServerListener.class.getSimpleName()+"], 这将导致没办法处理任何客户端请求");
        }
        return new DefaultWebSocketServerProtocolHandle(listenerMap);
    }

    @Bean
    @ConditionalOnBean(DefaultWebSocketServerComponent.class)
    public ServerHealthWebsocketEndpoint serverHealthWebsocketEndpoint() {
        return new ServerHealthWebsocketEndpoint(applicationContext.getStartupDate());
    }

}
